package org.flyby;

import com.google.common.collect.Lists;
import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.internal.HtmlHeaderContainer;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.PropertyListView;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.flyby.api.dao.*;
import org.flyby.api.persistence.Cart;
import org.flyby.api.persistence.Product;
import org.flyby.api.persistence.ProductOrderDetails;
import org.flyby.component.FlybyIndicatingAjaxLink;
import org.flyby.component.FlybyIndicatingAjaxSubmitLink;
import org.flyby.component.FlybyPage;

import java.util.List;

import static org.flyby.api.persistence.CodeTableData.*;

public class FlybyCartPage extends FlybyPage {

    private final WebMarkupContainer productsContainer;
    private final Label totalPriceLabel;
    private final Label totalWeightLabel;
    private final Label totalProductsLabel;

    @SpringBean
    private UserDao userDao;

    @SpringBean
    private ProductDao productDao;

    @SpringBean
    private ProductOrderDetailsDao productOrderDetailsDao;

    @SpringBean
    private CartDao cartDao;

    @SpringBean
    private CodeTableDataDao codeTableDataDao;

    private List<ProductOrderDetails> productsOrderDetailList = Lists.newArrayList();

    // Property model.
    private String barcode = "416021";
    private Integer units = 1;
    private FlybyIndicatingAjaxLink checkoutLink;
    private FlybyIndicatingAjaxSubmitLink addButton;

    @Override
    protected void onInitialize() {
        super.onInitialize();
        add(new FlybyResourcePackage());
    }

    public FlybyCartPage(Cart cart) {
        super(new CompoundPropertyModel<Cart>(cart));

        add(new Label("user.firstNameAndLastName"));

        setOutputMarkupId(true);

        productsContainer = new WebMarkupContainer("productContainer");
        productsContainer.setOutputMarkupPlaceholderTag(true);
        add(productsContainer.setVisible(false));


        add(totalPriceLabel = new Label("totalPrice"));
        totalPriceLabel.setOutputMarkupPlaceholderTag(true);
        add(totalWeightLabel = new Label("totalWeightKg"));
        totalWeightLabel.setOutputMarkupPlaceholderTag(true);
        add(totalProductsLabel = new Label("totalProducts"));
        totalProductsLabel.setOutputMarkupPlaceholderTag(true);

        PropertyListView productListView = new PropertyListView<ProductOrderDetails>("productListView", productsOrderDetailList) {

            @Override
            public void renderHead(HtmlHeaderContainer container) {
                super.renderHead(container);
                container.getHeaderResponse().render(OnDomReadyHeaderItem.forScript("$('#productListView').listview();"));
            }

            @Override
            protected void populateItem(ListItem productOrderDetailsListItem) {
                productOrderDetailsListItem.setOutputMarkupId(true);
                productOrderDetailsListItem.add(new Label("product.productName"));
                productOrderDetailsListItem.add(new Label("units"));
                productOrderDetailsListItem.add(new Label("totalOrderPrice"));
                productOrderDetailsListItem.add(increaseUnits(productOrderDetailsListItem));
                productOrderDetailsListItem.add(decreaseUnits(productOrderDetailsListItem));
                productOrderDetailsListItem.add(removeProductLink(productOrderDetailsListItem));

            }
        };

        productsContainer.add(productListView);
        addScanLink();
        checkOutLink();
    }

    private FlybyIndicatingAjaxLink removeProductLink(final ListItem productOrderDetailsListItem) {
        return new FlybyIndicatingAjaxLink("removeProduct") {
            @Override
            public void onClick(AjaxRequestTarget target) {
                ProductOrderDetails productOrderDetails = (ProductOrderDetails) productOrderDetailsListItem.getDefaultModelObject();
                productsOrderDetailList.remove(productOrderDetails);
                removeProductFromCart(productOrderDetails);
                refreshViewAfterShoppingAction(target);
            }
        };
    }

    private void refreshViewAfterShoppingAction(AjaxRequestTarget target) {
        target.add(totalWeightLabel);
        target.add(totalPriceLabel);
        target.add(totalProductsLabel);
        target.add(productsContainer);
    }

    private FlybyIndicatingAjaxLink decreaseUnits(final ListItem productOrderDetailsListItem) {
        return new FlybyIndicatingAjaxLink("decreaseUnits") {
            @Override
            public void onClick(AjaxRequestTarget target) {
                ProductOrderDetails productOrderDetails = (ProductOrderDetails) productOrderDetailsListItem.getDefaultModelObject();
                if (productOrderDetails.getUnits() > 1) {
                    removeProductFromCart(productOrderDetails);
                    productOrderDetails.setUnits(productOrderDetails.getUnits() - 1);
                    addProductOrderToCart(productOrderDetails);
                }
                target.add(productOrderDetailsListItem);
                refreshViewAfterShoppingAction(target);
            }
        };
    }

    private void removeProductFromCart(ProductOrderDetails productOrderDetails) {
        Cart cart = (Cart) getDefaultModelObject();
        cart.setTotalProducts(cart.getTotalProducts() - productOrderDetails.getUnits());
        cart.setTotalPrice(cart.getTotalPrice() - productOrderDetails.getTotalOrderPrice());
        cart.setTotalWeight(cart.getTotalWeight() - productOrderDetails.getOrderWeight());
    }

    private FlybyIndicatingAjaxLink increaseUnits(final ListItem productOrderDetailsListItem) {
        return new FlybyIndicatingAjaxLink("increaseUnits") {
            @Override
            public void onClick(AjaxRequestTarget target) {
                ProductOrderDetails productOrderDetails = (ProductOrderDetails) productOrderDetailsListItem.getDefaultModelObject();
                removeProductFromCart(productOrderDetails);
                productOrderDetails.setUnits(productOrderDetails.getUnits() + 1);
                addProductOrderToCart(productOrderDetails);
                target.add(productOrderDetailsListItem);
                refreshViewAfterShoppingAction(target);
            }
        };
    }

    private void checkOutLink() {
        add(checkoutLink = new FlybyIndicatingAjaxLink("checkoutLink") {
            @Override
            public void onClick(AjaxRequestTarget target) {
                Cart cart = (Cart) FlybyCartPage.this.getDefaultModelObject();
                setResponsePage(new CheckoutPage(cart));
            }
        });

        checkoutLink.setVisible(false);
        checkoutLink.setOutputMarkupPlaceholderTag(true);
    }

    private Cart saveCart() {
        for (ProductOrderDetails productOrderDetails : productsOrderDetailList) {
            productOrderDetailsDao.save(productOrderDetails);
        }

        Cart cart = (Cart) this.getDefaultModelObject();
        cart.setCartStatus(codeTableDataDao.findByTableHeaderCodeAndItemCode(DATA_CART_STATUS_WAIT_FOR_PAYMENT, HEADER_CART_STATUS_CODE));
        return cartDao.save(cart);

    }

    private void addProductButton(Form form) {

        form.add(addButton = new FlybyIndicatingAjaxSubmitLink("addButton") {

            @Override
            protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
                super.onSubmit(target, form);
                Product product = productDao.findByBarcode(barcode);
                if (product == null || product.isCart()) {
                    error("Product wasn't found");
                } else {
                    addProductIntoTheCart(target, product);
                    target.appendJavaScript("$('#productListView').listview();");
                }
            }
        });

        form.add(new TextField<String>("barcode", new PropertyModel<String>(this, "barcode")));

    }

    private void addScanLink() {
        final AbstractDefaultAjaxBehavior barcodeScan = new AbstractDefaultAjaxBehavior() {

            @Override
            protected void respond(AjaxRequestTarget target) {
                barcode = RequestCycle.get().getRequest().getRequestParameters().getParameterValue("barcode").toString();
                Product product = productDao.findByBarcode(barcode);
                if (product == null) {
                    error("Product wasn't found");
                } else if (product.isCart() && cartHasNotBeenSelected()) {
                    Cart cart = (Cart) FlybyCartPage.this.getDefaultModelObject();
                    cart.setCartBarcode(product.getBarcode());
                    cart.setCartStatus(codeTableDataDao.findByTableHeaderCodeAndItemCode(HEADER_CART_STATUS_CODE, DATA_CART_SELECTED));
                    cartDao.save(cart);

                    target.add(productsContainer.setVisible(true));
                    target.add(checkoutLink.setVisible(true));
                    target.appendJavaScript("$('#selectCartLabel').attr('style', 'visibility:hidden');");

                } else if (cartWasSelected() && !product.isCart()) {
                    addProductIntoTheCart(target, product);
                } else {
                    error("Product wasn't found");
                    target.add(((FlybyPage) getPage()).getFeedbackPanel());
                }
            }
        };

        FlybyIndicatingAjaxLink ajaxLink = new FlybyIndicatingAjaxLink("scanLink") {

            @Override
            public void onClick(AjaxRequestTarget target) {
                target.appendJavaScript("scanCode('" + barcodeScan.getCallbackUrl() + "')");
            }
        };
        add(ajaxLink);

        ajaxLink.add(barcodeScan);
    }

    private boolean cartWasSelected() {
        Cart cart = (Cart) getDefaultModelObject();
        return DATA_CART_SELECTED.equals(cart.getCartStatus().getItemCode());
    }

    private boolean cartHasNotBeenSelected() {
        return !cartWasSelected();
    }

    private void addProductIntoTheCart(AjaxRequestTarget target, Product product) {

        if (product != null) {

            ProductOrderDetails productOrderDetails = getProductOrderDetails(product);
            productsOrderDetailList.add(productOrderDetails);
            addProductOrderToCart(productOrderDetails);

            refreshViewAfterShoppingAction(target);
        } else {
            error("Product not found!");
        }
    }

    private ProductOrderDetails getProductOrderDetails(Product product) {
        Cart cart = (Cart) this.getDefaultModelObject();
        ProductOrderDetails productOrderDetails = new ProductOrderDetails();
        productOrderDetails.setCart(cart);
        productOrderDetails.setUnits(units);
        productOrderDetails.setProduct(product);
        productOrderDetails.setOrderPrice(product.getPrice() * units);
        productOrderDetails.setOrderWeight(product.getWeight() * units);

        return productOrderDetails;
    }

    private void addProductOrderToCart(ProductOrderDetails productOrderDetails) {
        Cart cart = (Cart) this.getDefaultModelObject();

        cart.setTotalWeight(cart.getTotalWeight() + productOrderDetails.getOrderWeight());
        cart.setTotalPrice(cart.getTotalPrice() + productOrderDetails.getOrderPrice());
        cart.setTotalProducts(cart.getTotalProducts() + productOrderDetails.getUnits());
    }


}
